---
title: Documents
description: How to create custom HTML documents for different routes in your Redwood SDK project
---

import { Aside, Steps } from '@astrojs/starlight/components';
import { FileTree } from '@astrojs/starlight/components';

In RedwoodSDK, Document components give you complete control over the HTML structure of each route. Unlike many frameworks that use a fixed HTML document structure, Redwood lets you define custom documents per route, controlling everything from the doctype to scripts and hydration strategy.

## A Basic Document

<Steps>
1. The starter project comes with a Document component.
    ```tsx title="src/app/Document.tsx"
    export const Document: React.FC<{ children: React.ReactNode }> = ({
      children,
    }) => (
      <html lang="en">
        <head>
          <meta charSet="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <title>RedwoodSDK App</title>
          <link rel="modulepreload" href="/src/client.tsx" />
        </head>
        <body>
          <div id="root">{children}</div>
          <script>import("/src/client.tsx")</script>
        </body>
      </html>
    );
    ```

2. Use the Document component in your routes:
    ```tsx title="src/worker.tsx" "Document" {4,8}
    import { defineApp } from 'rwsdk/worker'
    import { render, route } from 'rwsdk/router'

    import { Document } from '@/app/Document.tsx'
    import { HomePage } from '@/app/pages/HomePage.tsx'

    export default defineApp([
      render(Document, [
        route('/', HomePage),
      ])
    ])
    ```
</Steps>

## Multiple Document Types

One of the most powerful features of RedwoodSDK is the ability to use different Document components for different routes.

You can create a specialized Document component for a static document, a realtime document, or an application document.

Then, use different Documents for different routes:
```tsx title="src/worker.tsx" "StaticDocument" "ApplicationDocument" "RealtimeDocument" collapse={8-11}
import { defineApp } from 'rwsdk/worker'
import { render, route, prefix } from 'rwsdk/router'

import { StaticDocument } from '@/app/StaticDocument.tsx'
import { ApplicationDocument } from '@/app/ApplicationDocument.tsx'
import { RealtimeDocument } from '@/app/RealtimeDocument.tsx'

import { HomePage } from '@/app/pages/HomePage.tsx'
import { blogRoutes } from '@/app/routes/blog.tsx'
import { userRoutes } from '@/app/routes/user.tsx'
import { dashboardRoutes } from '@/app/routes/dashboard.tsx'

export default defineApp([
  render(StaticDocument, [
    route('/', HomePage),
    prefix('/blog', blogRoutes),
  ]),

  render(ApplicationDocument, [
    prefix('/app/user', userRoutes),
  ]),

  render(RealtimeDocument, [
    prefix('/app/dashboard', dashboardRoutes),
  ])
])
```

<Aside type="tip" title="Performance Optimization">
  Only include JavaScript when you need it. For static content like blog posts or marketing pages, consider using a StaticDocument with no client-side JavaScript for maximum performance.
</Aside>

## Further Reading

- [Blog Post: Per-Route Documents in RedwoodSDK: Total Control Over Your HTML](https://rwsdk.com/blog/redwoodsdk-multiple-documents)